Completed
Push — master ( 706e2b...22ecc8 )
by Sander
42s
created

_API.createCredential   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 4
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
1
/* global sjcl */
2
3
window.PAPI = (function () {
4
    var _encryptedFields = ['description', 'username', 'password', 'files', 'custom_fields', 'otp', 'email', 'tags', 'url'];
5
    var encryption_config = {
6
        adata: "",
7
        iter: 1000,
8
        ks: 256,
9
        mode: 'ccm',
10
        ts: 64
11
    };
12
    var _API = {
13
        username: '',
14
        password: '',
15
        host: '',
16
17
        getVaults: function (callback) {
18
            api_request({}, '/api/v2/vaults', 'GET', null, callback);
19
        },
20
        getVault: function (account, callback) {
21
            api_request(account, '/api/v2/vaults/' + account.vault.guid, 'GET', null, callback);
22
        },
23
        credentialsSet: function () {
24
            var hostSet = (typeof this.host !== 'undefined');
25
            var usernameSet = (this.username !== 'undefined');
26
            var passwordSet = (typeof this.password !== 'undefined');
27
            return (hostSet && usernameSet && passwordSet);
28
        },
29
        decryptString: function (ciphertext, _key) {
30
            ciphertext = window.atob(ciphertext);
31
            var rp = {};
32
            try {
33
                /** global: sjcl */
34
                return sjcl.decrypt(_key, ciphertext, encryption_config, rp);
35
            } catch (e) {
36
                throw e;
37
            }
38
        },
39
        decryptCredential: function (credential, key) {
40
            for (var i = 0; i < _encryptedFields.length; i++) {
41
                var field = _encryptedFields[i];
42
                var fieldValue = credential[field];
43
                var field_decrypted_value;
44
                try {
45
                    field_decrypted_value = this.decryptString(fieldValue, key);
46
                } catch (e) {
47
                    console.warn('Field' + field + ' in ' + credential.label + ' could not be parsed! Value:' + fieldValue);
48
                    //throw e;
49
                }
50
                try {
51
                    credential[field] = JSON.parse(field_decrypted_value);
52
                } catch (e) {
53
                    console.warn('Field' + field + ' in ' + credential.label + ' could not be parsed! Value:' + fieldValue);
54
                }
55
56
            }
57
            return credential;
58
59
        },
60
        encryptString: function (string, _key) {
61
            var rp = {};
62
            /** global: sjcl */
63
            var ct = sjcl.encrypt(_key, string, encryption_config, rp);
64
            return window.btoa(ct);
65
        },
66
        newCredential: function () {
67
            return {
68
                'credential_id': null,
69
                'guid': null,
70
                'vault_id': null,
71
                'label': null,
72
                'description': null,
73
                'created': null,
74
                'changed': null,
75
                'tags': [],
76
                'email': null,
77
                'username': null,
78
                'password': null,
79
                'url': null,
80
                'favicon': null,
81
                'renew_interval': null,
82
                'expire_time': 0,
83
                'delete_time': 0,
84
                'files': [],
85
                'custom_fields': [],
86
                'otp': {},
87
                'hidden': false
88
            };
89
        },
90
        encryptCredential: function (credential, _key) {
91
            for (var i = 0; i < _encryptedFields.length; i++) {
92
                var field = _encryptedFields[i];
93
                var fieldValue = credential[field];
94
                credential[field] = this.encryptString(JSON.stringify(fieldValue), _key);
95
            }
96
            return credential;
97
        },
98
        createCredential: function (account, credential, _key, callback) {
99
            credential = this.encryptCredential(credential, _key);
100
101
            credential.expire_time = new Date(credential.expire_time).getTime() / 1000;
102
            var _that = this;
103
104
            api_request(account, '/api/v2/credentials', 'POST', credential, function (r) {
105
                credential.credential_id = r.credential_id;
106
                credential.guid = r.guid;
107
                credential = _that.decryptCredential(credential, _key);
108
                callback(credential);
109
            });
110
        },
111
        encryptSharedCredential: function (credential, sharedKey, origKey) {
112
            var _credential = credential;
113
            _credential.shared_key = this.encryptString(sharedKey, origKey);
114
            var encrypted_fields = _encryptedFields;
115
            for (var i = 0; i < encrypted_fields.length; i++) {
116
                var field = encrypted_fields[i];
117
                var fieldValue = credential[field];
118
                _credential[field] = this.encryptString(JSON.stringify(fieldValue), sharedKey);
119
            }
120
            return _credential;
121
        },
122
        getCredendialsSharedWithUs: function (account, vault_guid, callback) {
123
            api_request(account, '/api/v2/sharing/vault/' + vault_guid + '/get', 'GET', null, callback);
124
        },
125
        decryptSharedCredential: function (credential, sharedKey) {
126
            var encrypted_fields = _encryptedFields;
127
            for (var i = 0; i < encrypted_fields.length; i++) {
128
                var field = encrypted_fields[i];
129
                var fieldValue = credential[field];
130
                var field_decrypted_value;
131
                if (credential.hasOwnProperty(field)) {
132
                    try {
133
                        field_decrypted_value = this.decryptString(fieldValue, sharedKey);
134
                    } catch (e) {
135
                        throw e;
136
                    }
137
                    try {
138
                        credential[field] = JSON.parse(field_decrypted_value);
139
                    } catch (e) {
140
                        console.warn('Field' + field + ' in ' + _credential.label + ' could not be parsed! Value:' + fieldValue);
0 ignored issues
show
Bug introduced by
The variable _credential seems to be never declared. If this is a global, consider adding a /** global: _credential */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
141
                        throw e;
142
                    }
143
                }
144
            }
145
            return credential;
146
            //console.log(this.decryptCredential(credental, decrypted_key));
147
        },
148
        updateCredential: function (account, credential, key, callback) {
149
            var origKey = key;
150
            var _credential, _key;
151
152
            if (!credential.hasOwnProperty('acl') && credential.hasOwnProperty('shared_key')) {
153
                if (credential.shared_key) {
154
                    _key = this.decryptString(credential.shared_key, key);
155
                }
156
            }
157
158
            if (credential.hasOwnProperty('acl')) {
159
                _key = this.decryptString(credential.acl.shared_key, key);
160
            }
161
162
            var regex = /(<([^>]+)>)/ig;
163
            if(credential.description && credential.description !== "") {
164
                credential.description = credential.description.replace(regex, "");
165
            }
166
167
168
            if (_key) {
169
                _credential = this.encryptSharedCredential(JSON.parse(JSON.stringify(credential)), _key, origKey);
170
            } else {
171
                _credential = this.encryptCredential(JSON.parse(JSON.stringify(credential)), key);
172
            }
173
            delete _credential.shared_key;
174
175
176
            credential.expire_time = new Date(credential.expire_time).getTime() / 1000;
177
178
            api_request(account, '/api/v2/credentials/' + credential.guid, 'PATCH', _credential, function () {
179
                callback(credential);
180
            });
181
        }
182
    };
183
184
    var api_request = function (account, endpoint, method, data, callback) {
185
186
        var host = (account.hasOwnProperty('nextcloud_host')) ? account.nextcloud_host : _API.host;
187
        var username = (account.hasOwnProperty('nextcloud_username')) ? account.nextcloud_username : _API.username;
188
        var password = (account.hasOwnProperty('nextcloud_password')) ? account.nextcloud_password : _API.password;
189
190
        var encodedLogin = btoa(username + ":" + password);
191
192
        var headers = new Headers();
0 ignored issues
show
Bug introduced by
The variable Headers seems to be never declared. If this is a global, consider adding a /** global: Headers */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
193
        headers.append('Authorization', 'Basic ' + encodedLogin);
194
        headers.append("Accept", " application/json, text/plain, */*");
195
        var opts = {
196
            method: method,
197
            headers: headers
198
199
        };
200
201
        if(data){
202
            // Prevent leakage of account data;
203
            if(data.hasOwnProperty('account')){
204
                delete data.account;
205
            }
206
        }
207
208
        if(method.toLowerCase() !== 'get'){
209
            headers.append('content-type','application/json;charset=UTF-8');
210
            opts.body = JSON.stringify(data);
211
        }
212
213
        var request = new Request(host + '/index.php/apps/passman' + endpoint, opts);
0 ignored issues
show
Bug introduced by
The variable Request seems to be never declared. If this is a global, consider adding a /** global: Request */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
214
215
        fetch(request).then(function(response){
216
            if(response.status !== 200){
217
                callback({error: true, result: {statusText: response.statusText, status: response.status}});
218
                return;
219
            }
220
221
            var contentType = response.headers.get("content-type");
222
            if(contentType && contentType.indexOf("application/json") !== -1) {
223
                return response.json().then(function(json) {
224
                    if(json){
225
                        callback(json);
226
                    } else {
227
                        callback({error: true, result: {statusText: 'Empty reply from server', status: 0}});
228
                    }
229
230
                });
231
            } else {
232
                callback({error: true, result: {statusText: 'Invalid reply from server', status: 0}});
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
233
            }
234
235
        }).catch(function (e) {
236
            API.notifications.create('Error', 'Error connecting to server (Error: '+ e +')');
237
            callback({error: true, result: {statusText: e, status: 0}});
238
        });
239
    };
240
241
    return _API;
242
}());